package com.ichoice.rabbitmq.rpc.helper;

import com.ichoice.hsp.cache.utils.RedisUtil;
import com.ichoice.rabbitmq.rpc.helper.client.ClientBlinding;
import com.ichoice.rabbitmq.rpc.helper.consts.CommonContant;
import com.ichoice.rabbitmq.rpc.helper.service.Consumer;
import com.ichoice.rabbitmq.rpc.helper.service.ServerBlinding;
import com.ichoice.rabbitmq.rpc.helper.sub.SubScribeHelper;
import org.apache.logging.log4j.util.Strings;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;
import java.net.UnknownHostException;

/**
 * @author xianrensawang
 * @since 2021/1/29
 */
@Configuration
@ConditionalOnProperty(prefix = "spring.rabbitmq.rpc", name = "enable", havingValue = "true", matchIfMissing = true)
public class RpcRabbitAutoConfig {

    @Resource
    private ConnectionFactory connectionFactory;

    @Resource
    private Environment environment;

    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${server.port}")
    private String port;


    @Bean(name = "rabbitTemplate")
    public RabbitTemplate createRabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
        // 设置消息转换,传输的json不设置会出现乱码  MappingJackson2MessageConverter
        // Jackson2JsonMessageConverter
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }


    @Bean("messageListenerContainer")
    public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        int coreSize = Runtime.getRuntime().availableProcessors();
        // 设置并发消费数量
        container.setConcurrentConsumers(coreSize/2);
        container.setMaxConcurrentConsumers(coreSize);
        // 手动确认
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        return container;
    }

    /**
     * 服务端消费者
     */
    @Bean("rpc-consumer")
    public Consumer serviceConsumer(RabbitTemplate rabbitTemplate) {
        SubScribeHelper.setTemplate(rabbitTemplate);
        return new Consumer(rabbitTemplate);
    }

    /**
     * 服务端绑定类
     */
    @Bean("rpc-server-blinding")
    public ServerBlinding serverBlinding(CachingConnectionFactory cachingConnectionFactory) {
        return new ServerBlinding(cachingConnectionFactory);
    }

    /**
     * 客户端绑定类
     */
    @Bean("rpc-client-blinding")
    public ClientBlinding clientBlinding(CachingConnectionFactory cachingConnectionFactory, RedisUtil redisUtil) {
        return new ClientBlinding(cachingConnectionFactory);
    }

    @Bean
    public RpcRabbit rpcRabbit(RabbitTemplate rabbitTemplate, ClientBlinding clientBlinding,ServerBlinding serverBlinding) throws UnknownHostException {
        String timeOut = environment.getProperty("spring.rabbitmq.rpc.timeOut");
        long timeOut1;
        if (Strings.isBlank(timeOut)) {
            timeOut1 = 10000L;
        } else {
            timeOut1 = Long.parseLong(timeOut);
        }
        String version = environment.getProperty("spring.cloud.nacos.discovery.metadata.version");
        if (Strings.isNotBlank(version)) {
            CommonContant.version = version;
        }
        RpcRabbitContext rpcRabbitContext = new RpcRabbitContext(rabbitTemplate, clientBlinding, timeOut1);
        rpcRabbitContext.init(applicationName, port);
        serverBlinding.init(applicationName);
        return rpcRabbitContext;
    }

    @Bean
    public ExecuteBlinding executeBlinding(Consumer consumers) {
        ExecuteBlinding blinding = new ExecuteBlinding(consumers);
        blinding.init(applicationName);
        return blinding;
    }


}
